package com.yjzx.bean;

import com.yjzx.interfaces.CommonClasses;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author yjzx
 * @date 2023/10/24
 * @description
 */
public class UpdateAnnotate extends JavassistInfo {
    String annotationName;

    List<Node> params;

    public UpdateAnnotate() {
    }

    public UpdateAnnotate(String annotationName, List<Node> params) {
        this.annotationName = annotationName;
        this.params = params;
    }

    @Override
    public void check() {
        this.checkParam(annotationName);
    }

    @Resource
    public static class Node {
        String type;
        String name;
        String value;
        UpdateAnnotate annotate;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public UpdateAnnotate getAnnotate() {
            return annotate;
        }

        public void setAnnotate(UpdateAnnotate annotate) {
            this.annotate = annotate;
        }
    }


    public String getAnnotationName() {
        return annotationName;
    }

    public void setAnnotationName(String annotationName) {
        this.annotationName = annotationName;
    }

    public List<Node> getParams() {
        return params;
    }

    public void setParams(List<Node> params) {
        this.params = params;
    }

    public AnnotationsAttribute toAnnotationAttribute(ClassPool pool, CtClass ctClass) {

        ClassFile classFile = ctClass.getClassFile();
        ConstPool constPool = classFile.getConstPool();
        Annotation annotation = this.toAnnotation(pool, ctClass);
        AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
        //把这个注解放到一个AnnotationsAttribute对象里面
        annotationsAttribute.addAnnotation(annotation);
        return annotationsAttribute;
    }



    public Annotation toAnnotation(ClassPool pool, CtClass ctClass) {
        this.check();
        ClassFile classFile = ctClass.getClassFile();
        ConstPool constPool = classFile.getConstPool();
        //创建要添加的注解
        Annotation annotation = new Annotation(CommonClasses.classNameConvert(annotationName), constPool);
        //设置注解中的属性和值
        params.forEach(node -> {
            Class<?> name = null;
            try {

                name = CommonClasses.getClass(pool, node.type);

                if (name.equals(Boolean.class)) {
                    annotation.addMemberValue(node.name, new BooleanMemberValue(Boolean.parseBoolean(node.value), constPool));
                } else if (name.equals(String.class)) {
                    annotation.addMemberValue(node.name, new StringMemberValue(node.value, constPool));
                } else if (name.equals(Integer.class)) {
                    annotation.addMemberValue(node.name, new IntegerMemberValue(Integer.parseInt(node.value), constPool));
                } else if (name.equals(Long.class)) {
                    annotation.addMemberValue(node.name, new LongMemberValue(Long.parseLong(node.value), constPool));
                } else if (name.equals(Class.class)) {
                    annotation.addMemberValue(node.name, new ClassMemberValue(Class.forName(node.value).getModifiers(), constPool));
                } else if (name.isAnnotation()){
                    annotation.addMemberValue(node.name, new AnnotationMemberValue(node.annotate.toAnnotation(pool, ctClass), constPool));
                }else {
                    throw new RuntimeException("需个人继承重新实现未处理的类型:"+node.type);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        return annotation;
    }
}
